package server

import (
	"encoding/json"
	"errors"
	c2 "gitee.com/enjoy_5/comment-rpc/internal/model/comment"
	c1 "gitee.com/enjoy_5/comment-rpc/proto/comment"
	"github.com/jinzhu/copier"
	"gorm.io/gorm"
)

func CommentToInfo(data *c2.Comment) *c1.CommentInfo {
	times := data.CreatedAt.Format("2006-01-02")
	c := new(c1.CommentInfo)
	err := json.Unmarshal([]byte(data.File), &c.File)
	if err != nil {
		return nil
	}

	return &c1.CommentInfo{
		ObjectId:   data.ObjectId,
		ObjectType: c1.TYPE(data.ObjectType),
		UserId:     data.UserId,
		File:       c.File,
		Rating:     data.Rating,
		Text:       data.Text,
		Pid:        data.Pid,
		Like:       data.Likes,
		Id:         int64(data.ID),
		CreateTime: times,
	}
}
func Check(v *c2.Comment) ([]*c1.SubComments, []string, error) {
	c := new(c1.CommentInfo)
	err := json.Unmarshal([]byte(v.File), &c.File)
	if err != nil {
		return nil, nil, err
	}
	subC, err := m().GetSubCommentById(int(v.ID))
	if err != nil {
		return nil, nil, err
	}
	var sub []*c1.SubComments
	err = copier.Copy(&sub, &subC)
	if err != nil {
		return nil, nil, err
	}
	return sub, c.File, nil
}
func CommentToInfoList(data []*c2.Comment) []*c1.CommentInfo {
	var com []*c1.CommentInfo
	for _, v := range data {
		times := v.CreatedAt.Format("2006-01-02")
		sub, file, err := Check(v)
		if err != nil {
			return nil
		}
		com = append(com, &c1.CommentInfo{
			ObjectId:    v.ObjectId,
			ObjectType:  c1.TYPE(v.ObjectType),
			UserId:      v.UserId,
			File:        file,
			Rating:      v.Rating,
			Text:        v.Text,
			Pid:         v.Pid,
			Like:        v.Likes,
			Id:          int64(v.ID),
			CreateTime:  times,
			SubComments: sub,
		})
	}
	return com
}

func InfoToComment(data *c1.CommentInfo) *c2.Comment {
	file, err := json.Marshal(data.File)
	if err != nil {
		return nil
	}
	return &c2.Comment{
		ObjectId:   data.ObjectId,
		ObjectType: int8(data.ObjectType),
		UserId:     data.UserId,
		File:       string(file),
		Rating:     data.Rating,
		Text:       data.Text,
		Pid:        data.Pid,
		Likes:      data.Like,
	}
}

func sift(rating c1.RATING) [2]int8 {
	switch rating {
	case c1.RATING_GOOD:
		return [2]int8{4, 5}
	case c1.RATING_ORDINARY:
		return [2]int8{3}
	case c1.RATING_LOW:
		return [2]int8{1, 2}
	default:
		return [2]int8{}
	}
}

func m() *c2.Comment {
	return new(c2.Comment)
}

func CreateComment(data *c1.CommentInfo) (*c1.CommentInfo, error) {
	comment, err := InfoToComment(data).CreateComment()
	if err != nil {
		return nil, err
	}
	return CommentToInfo(comment), nil
}

func DelComment(id int) error {
	err := m().DelComment(id)
	if err != nil {
		return err
	}
	return nil
}

func UpdateLike(l *c1.UpdateLike) error {
	r := new(c2.RecordCommentLike)
	rid, err := r.GetCommentLike(int(l.UserId), int(l.CommentId))
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		return err
	}

	c := new(c2.RecordCommentLike)
	var num int8
	switch rid.ID {
	case 0:
		num = 1
	default:
		num = -1
	}
	data := c2.RecordCommentLike{
		UserId:    l.UserId,
		CommentId: l.CommentId,
	}
	err = c.CommentLike(&data, num)
	if err != nil {
		return err
	}
	return nil
}
func GetCNumByRat(in *c1.GetCNumByRatReq) (*c1.GetCNumByRatResp, error) {
	var num []int64
	for _, rating := range in.Rating {
		to := sift(rating)
		rat, err := m().GetCNumByRating(to)
		if err != nil {
			return nil, err
		}
		num = append(num, rat)
	}
	return &c1.GetCNumByRatResp{Num: num}, nil
}
func GetCommentList(in *c1.GetListReq) ([]*c1.CommentInfo, error) {
	to := sift(in.Rating)

	list, err := redisCache(int(in.Page), int(in.Size), to, in.Order, in.ObjectId, int(in.ObjectType))
	if err != nil {
		return nil, err
	}
	return CommentToInfoList(list), nil
}

func redisCache(page, size int, to [2]int8, order c1.ORDER, objectId int64, objectType int) (list []*c2.Comment, err error) {
	switch order {
	case c1.ORDER_DESC_BY_TIME:
		list, err = m().DescOrderByTime(page, size, int(objectId), to, objectType)
		if err != nil {
			return
		}
	case c1.ORDER_ASC_BY_TIME:
		list, err = m().AscOrderByTime(page, size, int(objectId), to, objectType)
		if err != nil {
			return
		}
	case c1.ORDER_NORMAL:
		list, err = m().GetCommentList(page, size, int(objectId), to, objectType)
		if err != nil {
			return
		}
	}
	return
}
